<!doctype html>
<meta charset="utf-8"/>
<title>oj r7</title>
<body>
<script>(function(){

// RequireJS 2.0.2  http://github.com/jrburke/requirejs
var requirejs,require,define;
(function(Z){function w(b){return J.call(b)==="[object Function]"}function G(b){return J.call(b)==="[object Array]"}function q(b,d){if(b){var f;for(f=0;f<b.length;f+=1)if(b[f]&&d(b[f],f,b))break}}function N(b,d){if(b){var f;for(f=b.length-1;f>-1;f-=1)if(b[f]&&d(b[f],f,b))break}}function x(b,d){for(var f in b)if(b.hasOwnProperty(f)&&d(b[f],f))break}function K(b,d,f,g){d&&x(d,function(d,k){if(f||!b.hasOwnProperty(k))g&&typeof d!=="string"?(b[k]||(b[k]={}),K(b[k],d,f,g)):b[k]=d});return b}function s(b,
d){return function(){return d.apply(b,arguments)}}function $(b){if(!b)return b;var d=Z;q(b.split("."),function(b){d=d[b]});return d}function aa(b,d,f){return function(){var g=ga.call(arguments,0),e;if(f&&w(e=g[g.length-1]))e.__requireJsBuild=!0;g.push(d);return b.apply(null,g)}}function ba(b,d,f){q([["toUrl"],["undef"],["defined","requireDefined"],["specified","requireSpecified"]],function(g){var e=g[1]||g[0];b[g[0]]=d?aa(d[e],f):function(){var b=t[O];return b[e].apply(b,arguments)}})}function H(b,
d,f,g){d=Error(d+"\nhttp://requirejs.org/docs/errors.html#"+b);d.requireType=b;d.requireModules=g;if(f)d.originalError=f;return d}function ha(){if(I&&I.readyState==="interactive")return I;N(document.getElementsByTagName("script"),function(b){if(b.readyState==="interactive")return I=b});return I}var ia=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ja=/require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,ca=/\.js$/,ka=/^\.\//,J=Object.prototype.toString,y=Array.prototype,ga=y.slice,la=y.splice,u=!!(typeof window!==
"undefined"&&navigator&&document),da=!u&&typeof importScripts!=="undefined",ma=u&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,O="_",S=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",t={},p={},P=[],L=!1,k,v,C,z,D,I,E,ea,fa;if(typeof define==="undefined"){if(typeof requirejs!=="undefined"){if(w(requirejs))return;p=requirejs;requirejs=void 0}typeof require!=="undefined"&&!w(require)&&(p=require,require=void 0);k=requirejs=function(b,d,f,g){var e=O,r;!G(b)&&
typeof b!=="string"&&(r=b,G(d)?(b=d,d=f,f=g):b=[]);if(r&&r.context)e=r.context;(g=t[e])||(g=t[e]=k.s.newContext(e));r&&g.configure(r);return g.require(b,d,f)};k.config=function(b){return k(b)};require||(require=k);k.version="2.0.2";k.jsExtRegExp=/^\/|:|\?|\.js$/;k.isBrowser=u;y=k.s={contexts:t,newContext:function(b){function d(a,c,l){var A=c&&c.split("/"),b=m.map,i=b&&b["*"],h,d,f,e;if(a&&a.charAt(0)===".")if(c){A=m.pkgs[c]?[c]:A.slice(0,A.length-1);c=a=A.concat(a.split("/"));for(h=0;c[h];h+=1)if(d=
c[h],d===".")c.splice(h,1),h-=1;else if(d==="..")if(h===1&&(c[2]===".."||c[0]===".."))break;else h>0&&(c.splice(h-1,2),h-=2);h=m.pkgs[c=a[0]];a=a.join("/");h&&a===c+"/"+h.main&&(a=c)}else a.indexOf("./")===0&&(a=a.substring(2));if(l&&(A||i)&&b){c=a.split("/");for(h=c.length;h>0;h-=1){f=c.slice(0,h).join("/");if(A)for(d=A.length;d>0;d-=1)if(l=b[A.slice(0,d).join("/")])if(l=l[f]){e=l;break}!e&&i&&i[f]&&(e=i[f]);if(e){c.splice(0,h,e);a=c.join("/");break}}}return a}function f(a){u&&q(document.getElementsByTagName("script"),
function(c){if(c.getAttribute("data-requiremodule")===a&&c.getAttribute("data-requirecontext")===j.contextName)return c.parentNode.removeChild(c),!0})}function g(a){var c=m.paths[a];if(c&&G(c)&&c.length>1)return f(a),c.shift(),j.undef(a),j.require([a]),!0}function e(a,c,l,b){var T=a?a.indexOf("!"):-1,i=null,h=c?c.name:null,f=a,e=!0,g="",k,m;a||(e=!1,a="_@r"+(N+=1));T!==-1&&(i=a.substring(0,T),a=a.substring(T+1,a.length));i&&(i=d(i,h,b),m=o[i]);a&&(i?g=m&&m.normalize?m.normalize(a,function(a){return d(a,
h,b)}):d(a,h,b):(g=d(a,h,b),k=j.nameToUrl(a,null,c)));a=i&&!m&&!l?"_unnormalized"+(O+=1):"";return{prefix:i,name:g,parentMap:c,unnormalized:!!a,url:k,originalName:f,isDefine:e,id:(i?i+"!"+g:g)+a}}function r(a){var c=a.id,l=n[c];l||(l=n[c]=new j.Module(a));return l}function p(a,c,l){var b=a.id,d=n[b];if(o.hasOwnProperty(b)&&(!d||d.defineEmitComplete))c==="defined"&&l(o[b]);else r(a).on(c,l)}function B(a,c){var l=a.requireModules,b=!1;if(c)c(a);else if(q(l,function(c){if(c=n[c])c.error=a,c.events.error&&
(b=!0,c.emit("error",a))}),!b)k.onError(a)}function v(){P.length&&(la.apply(F,[F.length-1,0].concat(P)),P=[])}function t(a,c,l){a=a&&a.map;c=aa(l||j.require,a,c);ba(c,j,a);c.isBrowser=u;return c}function y(a){delete n[a];q(M,function(c,l){if(c.map.id===a)return M.splice(l,1),c.defined||(j.waitCount-=1),!0})}function z(a,c){var l=a.map.id,b=a.depMaps,d;if(a.inited){if(c[l])return a;c[l]=!0;q(b,function(a){if(a=n[a.id])return!a.inited||!a.enabled?(d=null,delete c[l],!0):d=z(a,K({},c))});return d}}function C(a,
c,b){var d=a.map.id,e=a.depMaps;if(a.inited&&a.map.isDefine){if(c[d])return o[d];c[d]=a;q(e,function(i){var i=i.id,h=n[i];!Q[i]&&h&&(!h.inited||!h.enabled?b[d]=!0:(h=C(h,c,b),b[i]||a.defineDepById(i,h)))});a.check(!0);return o[d]}}function D(a){a.check()}function E(){var a=m.waitSeconds*1E3,c=a&&j.startTime+a<(new Date).getTime(),b=[],d=!1,e=!0,i,h,k;if(!U){U=!0;x(n,function(a){i=a.map;h=i.id;if(a.enabled&&!a.error)if(!a.inited&&c)g(h)?d=k=!0:(b.push(h),f(h));else if(!a.inited&&a.fetched&&i.isDefine&&
(d=!0,!i.prefix))return e=!1});if(c&&b.length)return a=H("timeout","Load timeout for modules: "+b,null,b),a.contextName=j.contextName,B(a);e&&(q(M,function(a){if(!a.defined){var a=z(a,{}),c={};a&&(C(a,c,{}),x(c,D))}}),x(n,D));if((!c||k)&&d)if((u||da)&&!V)V=setTimeout(function(){V=0;E()},50);U=!1}}function W(a){r(e(a[0],null,!0)).init(a[1],a[2])}function J(a){var a=a.currentTarget||a.srcElement,c=j.onScriptLoad;a.detachEvent&&!S?a.detachEvent("onreadystatechange",c):a.removeEventListener("load",c,
!1);c=j.onScriptError;a.detachEvent&&!S||a.removeEventListener("error",c,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}var m={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{}},n={},X={},F=[],o={},R={},N=1,O=1,M=[],U,Y,j,Q,V;Q={require:function(a){return t(a)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports=o[a.map.id]={}},module:function(a){return a.module={id:a.map.id,uri:a.map.url,config:function(){return m.config&&m.config[a.map.id]||{}},exports:o[a.map.id]}}};
Y=function(a){this.events=X[a.id]||{};this.map=a;this.shim=m.shim[a.id];this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Y.prototype={init:function(a,c,b,d){d=d||{};if(!this.inited){this.factory=c;if(b)this.on("error",b);else this.events.error&&(b=s(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.depMaps.rjsSkipMap=a.rjsSkipMap;this.errback=b;this.inited=!0;this.ignore=d.ignore;d.enabled||this.enabled?this.enable():this.check()}},defineDepById:function(a,
c){var b;q(this.depMaps,function(c,d){if(c.id===a)return b=d,!0});return this.defineDep(b,c)},defineDep:function(a,c){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=c)},fetch:function(){if(!this.fetched){this.fetched=!0;j.startTime=(new Date).getTime();var a=this.map;if(this.shim)t(this,!0)(this.shim.deps||[],s(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=this.map.url;R[a]||
(R[a]=!0,j.load(this.map.id,a))},check:function(a){if(this.enabled&&!this.enabling){var c=this.map.id,b=this.depExports,d=this.exports,e=this.factory,i;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(this.depCount<1&&!this.defined){if(w(e)){if(this.events.error)try{d=j.execCb(c,e,b,d)}catch(h){i=h}else d=j.execCb(c,e,b,d);if(this.map.isDefine)if((b=this.module)&&b.exports!==void 0&&b.exports!==this.exports)d=b.exports;else if(d===void 0&&this.usingExports)d=
this.exports;if(i)return i.requireMap=this.map,i.requireModules=[this.map.id],i.requireType="define",B(this.error=i)}else d=e;this.exports=d;if(this.map.isDefine&&!this.ignore&&(o[c]=d,k.onResourceLoad))k.onResourceLoad(j,this.map,this.depMaps);delete n[c];this.defined=!0;j.waitCount-=1;j.waitCount===0&&(M=[])}this.defining=!1;if(!a&&this.defined&&!this.defineEmitted)this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0}}else this.fetch()}},callPlugin:function(){var a=
this.map,c=a.id,b=e(a.prefix,null,!1,!0);p(b,"defined",s(this,function(b){var l=this.map.name,i=this.map.parentMap?this.map.parentMap.name:null;if(this.map.unnormalized){if(b.normalize&&(l=b.normalize(l,function(a){return d(a,i,!0)})||""),b=e(a.prefix+"!"+l,this.map.parentMap,!1,!0),p(b,"defined",s(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),b=n[b.id]){if(this.events.error)b.on("error",s(this,function(a){this.emit("error",a)}));b.enable()}}else l=s(this,function(a){this.init([],
function(){return a},null,{enabled:!0})}),l.error=s(this,function(a){this.inited=!0;this.error=a;a.requireModules=[c];x(n,function(a){a.map.id.indexOf(c+"_unnormalized")===0&&y(a.map.id)});B(a)}),l.fromText=function(a,c){var b=L;b&&(L=!1);r(e(a));k.exec(c);b&&(L=!0);j.completeLoad(a)},b.load(a.name,t(a.parentMap,!0,function(a,c){a.rjsSkipMap=!0;return j.require(a,c)}),l,m)}));j.enable(b,this);this.pluginMaps[b.id]=b},enable:function(){this.enabled=!0;if(!this.waitPushed)M.push(this),j.waitCount+=
1,this.waitPushed=!0;this.enabling=!0;q(this.depMaps,s(this,function(a,c){var b,d;if(typeof a==="string"){a=e(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.depMaps.rjsSkipMap);this.depMaps[c]=a;if(b=Q[a.id]){this.depExports[c]=b(this);return}this.depCount+=1;p(a,"defined",s(this,function(a){this.defineDep(c,a);this.check()}));this.errback&&p(a,"error",this.errback)}b=a.id;d=n[b];!Q[b]&&d&&!d.enabled&&j.enable(a,this)}));x(this.pluginMaps,s(this,function(a){var c=n[a.id];c&&!c.enabled&&
j.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,c){var b=this.events[a];b||(b=this.events[a]=[]);b.push(c)},emit:function(a,c){q(this.events[a],function(a){a(c)});a==="error"&&delete this.events[a]}};return j={config:m,contextName:b,registry:n,defined:o,urlFetched:R,waitCount:0,defQueue:F,Module:Y,makeModuleMap:e,configure:function(a){a.baseUrl&&a.baseUrl.charAt(a.baseUrl.length-1)!=="/"&&(a.baseUrl+="/");var c=m.pkgs,b=m.shim,d=m.paths,f=m.map;K(m,a,!0);m.paths=K(d,a.paths,!0);if(a.map)m.map=
K(f||{},a.map,!0,!0);if(a.shim)x(a.shim,function(a,c){G(a)&&(a={deps:a});if(a.exports&&!a.exports.__buildReady)a.exports=j.makeShimExports(a.exports);b[c]=a}),m.shim=b;if(a.packages)q(a.packages,function(a){a=typeof a==="string"?{name:a}:a;c[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(ca,"")}}),m.pkgs=c;x(n,function(a,c){a.map=e(c)});if(a.deps||a.callback)j.require(a.deps||[],a.callback)},makeShimExports:function(a){var c;return typeof a==="string"?
(c=function(){return $(a)},c.exports=a,c):function(){return a.apply(Z,arguments)}},requireDefined:function(a,c){var b=e(a,c,!1,!0).id;return o.hasOwnProperty(b)},requireSpecified:function(a,c){a=e(a,c,!1,!0).id;return o.hasOwnProperty(a)||n.hasOwnProperty(a)},require:function(a,c,d,f){var g;if(typeof a==="string"){if(w(c))return B(H("requireargs","Invalid require call"),d);if(k.get)return k.get(j,a,c);a=e(a,c,!1,!0);a=a.id;return!o.hasOwnProperty(a)?B(H("notloaded",'Module name "'+a+'" has not been loaded yet for context: '+
b)):o[a]}d&&!w(d)&&(f=d,d=void 0);c&&!w(c)&&(f=c,c=void 0);for(v();F.length;)if(g=F.shift(),g[0]===null)return B(H("mismatch","Mismatched anonymous define() module: "+g[g.length-1]));else W(g);r(e(null,f)).init(a,c,d,{enabled:!0});E();return j.require},undef:function(a){var c=e(a,null,!0),b=n[a];delete o[a];delete R[c.url];delete X[a];if(b){if(b.events.defined)X[a]=b.events;y(a)}},enable:function(a){n[a.id]&&r(a).enable()},completeLoad:function(a){var c=m.shim[a]||{},b=c.exports&&c.exports.exports,
d,e;for(v();F.length;){e=F.shift();if(e[0]===null){e[0]=a;if(d)break;d=!0}else e[0]===a&&(d=!0);W(e)}e=n[a];if(!d&&!o[a]&&e&&!e.inited)if(m.enforceDefine&&(!b||!$(b)))if(g(a))return;else return B(H("nodefine","No define call for "+a,null,[a]));else W([a,c.deps||[],c.exports]);E()},toUrl:function(a,b){var d=a.lastIndexOf("."),e=null;d!==-1&&(e=a.substring(d,a.length),a=a.substring(0,d));return j.nameToUrl(a,e,b)},nameToUrl:function(a,b,e){var f,g,i,h,j,a=d(a,e&&e.id,!0);if(k.jsExtRegExp.test(a))b=
a+(b||"");else{f=m.paths;g=m.pkgs;e=a.split("/");for(h=e.length;h>0;h-=1)if(j=e.slice(0,h).join("/"),i=g[j],j=f[j]){G(j)&&(j=j[0]);e.splice(0,h,j);break}else if(i){a=a===i.name?i.location+"/"+i.main:i.location;e.splice(0,h,a);break}b=e.join("/")+(b||".js");b=(b.charAt(0)==="/"||b.match(/^[\w\+\.\-]+:/)?"":m.baseUrl)+b}return m.urlArgs?b+((b.indexOf("?")===-1?"?":"&")+m.urlArgs):b},load:function(a,b){k.load(j,a,b)},execCb:function(a,b,d,e){return b.apply(e,d)},onScriptLoad:function(a){if(a.type===
"load"||ma.test((a.currentTarget||a.srcElement).readyState))I=null,a=J(a),j.completeLoad(a.id)},onScriptError:function(a){var b=J(a);if(!g(b.id))return B(H("scripterror","Script error",a,[b.id]))}}}};k({});ba(k);if(u&&(v=y.head=document.getElementsByTagName("head")[0],C=document.getElementsByTagName("base")[0]))v=y.head=C.parentNode;k.onError=function(b){throw b;};k.load=function(b,d,f){var g=b&&b.config||{},e;if(u)return e=g.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):
document.createElement("script"),e.type=g.scriptType||"text/javascript",e.charset="utf-8",e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",d),e.attachEvent&&!(e.attachEvent.toString&&e.attachEvent.toString().indexOf("[native code")<0)&&!S?(L=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=f,E=e,C?v.insertBefore(e,C):v.appendChild(e),E=null,e;else da&&(importScripts(f),
b.completeLoad(d))};u&&N(document.getElementsByTagName("script"),function(b){if(!v)v=b.parentNode;if(z=b.getAttribute("data-main")){D=z.split("/");ea=D.pop();fa=D.length?D.join("/")+"/":"./";if(!p.baseUrl)p.baseUrl=fa;z=ea.replace(ca,"");p.deps=p.deps?p.deps.concat(z):[z];return!0}});define=function(b,d,f){var g,e;typeof b!=="string"&&(f=d,d=b,b=null);G(d)||(f=d,d=[]);!d.length&&w(f)&&f.length&&(f.toString().replace(ia,"").replace(ja,function(b,e){d.push(e)}),d=(f.length===1?["require"]:["require",
"exports","module"]).concat(d));if(L&&(g=E||ha()))b||(b=g.getAttribute("data-requiremodule")),e=t[g.getAttribute("data-requirecontext")];(e?e.defQueue:P).push([b,d,f])};define.amd={jQuery:!0};k.exec=function(b){return eval(b)};k(p)}})(this);
window.requirejs=requirejs;window.require=require;window.define=define
requirejs.config({waitSeconds:15})



window.OJ = {}
    
OJ.version = document.title

// main module name 'some/module'
OJ.__main__ = window.location.pathname.slice(1)

// arguments array [['arg', 'value'], ['arg', 'value'], ...]
OJ.args = window.location.search.slice(1).split('&')
var i;for(i in OJ.args)OJ.args[i]=OJ.args[i].split('=')

// set the document title to the module name
document.title=OJ.__main__


// pollute the global namespace with some helpers and shims

window.type = function(obj) {
    /**
     *>type(obj)
     *
     * Returns the type of obj.
     */
        
    return (obj === window) ? "global" : Object.prototype.toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase()

}



window.print = function(obj) {
    /**
     *>print(obj)
     *
     * Prints obj to the console.
     */
    
    console.log(obj)

}



window.requestAnimationFrame || (window.requestAnimationFrame = 
  window.webkitRequestAnimationFrame || 
  window.mozRequestAnimationFrame    || 
  window.oRequestAnimationFrame      || 
  window.msRequestAnimationFrame     || 
  function(callback, element) {
    return window.setTimeout(callback, 1000 / 60)
})




// oj functions

OJ.isError = function(obj) {
    /**
     *>oj.isError(obj)
     *
     *Returns true if obj represents an error; otherwise false;
     */
    
    if (typeof obj==='string')
        try{obj=JSON.parse(obj)}catch(err){}
    
    return (typeof obj==='object' && obj.hasOwnProperty('error'))

}



OJ.element = function(parent, tag, classes, attributes, content) {
    /**
     *>oj.element(parent, 'tag', 'classes', {attributes}, [content])
     *
     * Creates a HTMLElement instance.
     * 
     * Parent is an optional HTMLElement to attach the new HTMLElement
     * named tag. A class and attributes will be assigned if specifiec,
     * with a list of HTMLElements and strings appended as content.
     * 
     *. var container = element.create(document.body, 'div', 'container', [
     *.   element.create('p', ['A paragraph inside a div'])
     *. ]);
     */
    
    if (typeof parent === 'string') {

        content = attributes
        attributes = classes
        classes = tag
        tag = parent

    }
    
    if (typeof tag !== 'string')
        throw 'Expected a string for name but received ' + typeof tag
    
    
    var el = document.createElement(tag)
    
    if (typeof classes === 'string')
        el.setAttribute('class', classes)

    else {

        content = attributes
        attributes = classes

    }
    
    if (type(attributes) === 'object')
        Object.keys(attributes).forEach(function (attrib) {
            el.setAttribute(attrib, attributes[attrib])
        })

    else
        content = attributes
    
    
    if (type(content) === 'array') {

        tag = -1

        while (++tag < content.length) {

            if (content[tag] instanceof HTMLElement)
                el.appendChild(content[tag])

            else if (typeof content[tag] === 'string') {

                el.innerHTML += content[tag]
                if (tag < content.length - 1)
                    el.innerHTML += '\n'

            }

        }

    }
    
    if (parent instanceof HTMLElement)
        parent.appendChild(el)
    
    
    return el

}



OJ.absoluteTop = function(el) {
    /**
     *>oj.absoluteTop(el)
     *
     * Returns the absolute top position of the element.
     */
    
    var top = 0
    
    while (el != null) {
        top += el.offsetTop
        el = el.offsetParent
    }
    
    return top

}



OJ.absoluteLeft = function(el) {
    /**
     *>oj.absoluteLeft(el)
     *
     * Returns the absolute left position of the element.
     */
    
    var left = 0
    
    while (el != null) {

        left += el.offsetLeft
        el = el.offsetParent

    }
    
    return left

}



OJ.tokenise = function(string) {
    /**
     *> OJ.tokenise('string')
     * 
     * Returns an array of tokens from string
     */
    
    var keywords = [
            'break', 'case', 'catch', 'continue', 'debugger',
            'default', 'delete', 'do', 'else', 'finally', 'for',
            'function', 'if', 'in', 'instanceof', 'new', 'return',
            'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void',
            'while', 'with', 'undefined', 'null', 'true', 'false'
        ],
        result = [],
        i = 0,
        c = string.charAt(i),
        valu,
        q,
    
    until = function (r) {
        for (;;) {
            c = string.charAt(++i)

            if (!c || c === r)
                break
                
                value += c
        }
    },
    
    upto = function (r) {
        for (;;) {
            c = string.charAt(++i)

            if (!c)
                break

            value += c

            if (r.test(value)) {
                c = string.charAt(++i)
                break
            }
        }
    },
    
    still = function (r) {
        for (;;) {
            c = string.charAt(++i)

            if (c !== r)
                break
            
                value += c;
        }
    }
    
    while (c) {
        if (c === ' ') {

            // space
            value = c
            still(' ')
            result.push({type: 1, value: value})

        } else if (c === '\n') {

            // line break
            value = c
            still('\n')
            result.push({type: 2, value: value})

        } else if (c === '/' && string.charAt(i + 1) === '/') {

            // line comment
            value = c
            until('\n')
            result.push({type: 3, value: value})

        } else if (c === '/' && string.charAt(i + 1) === '*') {

            // multiline comment
            value = c
            upto(/\*\/$/)
            result.push({type: 3, value: value})

        } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c === '$' || c === '_') {

            // name or keyword
            value = c
            for (;;) {
                c = string.charAt(++i)
                if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '$' || c === '_')
                    value += c
                else
                    break
                
            }
            
            if (keywords.indexOf(value) > -1)
                // keyword
                result.push({type: 4, value: value})
            else
                // name
                result.push({type: 5, value: value})
            
        } else if (c >= '0' && c <= '9') {

            // number
            value = c
            for (;;) {
                c = string.charAt(++i)
                if ((c >= '0' && c <= '9') || c === '.')
                    value += c
                else
                    break
            }
            result.push({type: 6, value: value})

        } else if (c === '\'' || c === '"') {

            // string
            value = c
            q = c
            for (;;) {
                c = string.charAt(++i)

                if (!c || c === '\n')
                    break
                
                value += c
                if (c === '\\') {
                    c = string.charAt(++i)
                    value += c
                } else if (c === q) {
                    c = string.charAt(++i)
                    break
                }
            }

            result.push({type: 7, value: value})

        } else {
            // operator
            result.push({type: 0, value: c})
            c = string.charAt(++i)
        }
    }
    
    return result
    
}



/**
=OJ.REMOTE - Open remote resources by URL

Functions for fetching data across the Internet. 

*/


OJ.REMOTE = {}

OJ.REMOTE.ID = (new Date).getTime()

OJ.REMOTE.TIMEOUT = 300000





OJ.REMOTE.jsonp = function(url, callbackarg, args, callback) {
    /**
     *> OJ.REMOTE.jsonp('url', 'callbackarg', 'args', callback)
     *
     * Read JSONP from URL.
     *
     *. OJ.REMOTE.jsonp('http://jsonp.url.com/', 'callback=', 'arg1=value&arg2=value', function (msg) {
     *.     var json = JSON.parse(msg);
     *. });
     */
    
    var cb     = 'jsonp_' + String(++OJ.REMOTE.ID),
        timer  = setTimeout(function() {window[cb]({'error': 'timeout'});}, OJ.REMOTE.TIMEOUT),
        script = document.createElement('script')
    
    if (typeof args === 'undefined' || args.length === 0)
        args = ''
    else
        args = '&' + args
    
    script.src = url + '?' + callbackarg + cb + args
    
    window[cb] = function () {
        clearTimeout(timer)
        try {
            delete window[cb]
        } catch(e) {
            window[cb] = null
        }

        if (typeof callback === 'function')
            callback.apply(this, arguments)
        
        document.body.removeChild(script)
    }
    
    document.body.appendChild(script)

}



OJ.REMOTE.image = function(url, callback) {
    /**
     *> OJ.REMOTE.img('url', callback)
     *
     * Read an Image from URL.
     *
     *. OJ.REMOTE.img('http://url.com/image.jpg', function (image) {
     *.     var width = image.width;
     *. });
     */
    
    var img = document.createElement('img')
    
    img.src = '/proxy/' + encodeURIComponent(url)
    img.onload = function () {
        document.body.removeChild(img)
        if (typeof callback === 'function')
            callback(img)
    }
    
    document.body.appendChild(img)

}



OJ.REMOTE.script = function(url, callback) {
    /**
     *> OJ.REMOTE.script('url', callback)
     *
     * Load a script from URL.
     *
     *. OJ.REMOTE.script('http://url.com/script.js')
     *
     */
    
    var script = document.createElement('script')
    
    script.src = url
    
    script.onload = function () {
        if (typeof callback === 'function')
            callback(script)
    }
    
    document.body.appendChild(script)

}





/**
=OJ.OS - Operating system interface

File system operations.

*/


OJ.OS = {}


OJ.OS.environ = {
    cwd: '/'
}



OJ.OS.system = function(path, commands, callback) {
    /**
     *> OJ.OS.system('path', [commands], callback)
     * 
     * Execute a list of server commands.
     * 
     */
    
    OJ.REMOTE.jsonp(path, 'P/', commands.join('&'), callback)

}



OJ.OS.identity = function(destUrl, callback) {
    /**
     *> OJ.OS.identity('destUrl', callback)
     * 
     * Get user identity.
     * 
     */
    
    OJ.OS.system('/', ['I/' + destUrl], callback)

}



OJ.OS.logout = function(destUrl, callback) {
    /**
     *> OJ.OS.logout('destUrl', callback)
     * 
     * Logs user out.
     * 
     */
    
    OJ.OS.system('/', ['E/' + destUrl], callback)

}



OJ.OS.read = function(path, callback) {
    /**
     *> OJ.OS.read('path', callback)
     * 
     * Reads a path from the server.
     * 
     */

    OJ.OS.system(path, ['R/'], callback)

}



OJ.OS.write = function(path, content, callback) {
    /**
     *> OJ.OS.write('path', 'content', callback)
     * 
     * Write content to path.
     * 
     */
    
    OJ.OS.system(path, ['W/' + content], callback)

}



OJ.OS.chdir = function(path, callback) {
    /**
     *> OJ.OS.chdir('path', callback)
     * 
     * Changes the current working directory.
     * 
     */
    
    path = OJ.OS.PATH.abspath(path + '/')
    OJ.OS.read(path, function(read) {
        if (!OJ.isError(read))
            OJ.OS.environ.cwd = path
        
        if (typeof callback === 'function')
           callback(read)
        
    })

}



OJ.OS.mkdir = function(path, callback) {
    /**
     *> OJ.OS.mkdir('path', callback)
     * 
     * Creates a new directory.
     * 
     */
    
    OJ.OS.system(OJ.OS.PATH.abspath(path + '/'), ['M/'], callback)

}



OJ.OS.rmdir = function(path, callback) {
    /**
     *> OJ.OS.rmdir('path', callback)
     * 
     * Removes a directory.
     * 
     */

    OJ.OS.system(OJ.OS.PATH.abspath(path + '/'), ['X/'], callback)

}



OJ.OS.listdir = function(path, callback) {
    /**
     *> OJ.OS.listdir('path', callback)
     * 
     * Returns a list of files and directories.
     * 
     */
    
    if (typeof path === 'undefined' || path === '')
        path = '.'
    
    
    OJ.OS.read(OJ.OS.PATH.abspath(path + '/'), function (m) {
        try {
            m = JSON.parse(m)
        } catch (err) {}

        if (typeof callback === 'function') {
            callback(m)
        }
    })

}



OJ.OS.move = function(src, dst, callback) {
    /**
     *> OJ.OS.move('src', 'dst', callback)
     * 
     * Moves a file or directory from src to dst.
     * 
     */

    OJ.OS.system(OJ.OS.PATH.abspath(src), ['N/' + OJ.OS.PATH.abspath(dst)], callback)

}



OJ.OS.remove = function(path, callback) {
    /**
     *> OJ.OS.remove('path', callback)
     * 
     * Removes file at path.
     * 
     */
    
    OJ.OS.system(OJ.OS.PATH.abspath(path), ['D/'], callback)

}



OJ.OS.concat = function(paths, clean, callback) {
    /**
     *> OJ.OS.concat([paths], clean, callback)
     * 
     * Concatenates a list of files to one file.
     *
     *. OJ.OS.concat( args, false, function (msg) {
     *.     var error = OJ.isError(msg);
     *. });
     *
     */
    
    var path = OJ.OS.PATH.abspath(paths.pop()),
        cmd = (clean) ? 'CR/' : 'C/',
        i = paths.length
    
    while (--i)
        paths[i] = OJ.OS.PATH.abspath(paths[i])
    
    
    OJ.OS.system(path, [cmd + paths.join('!')], callback)

}



OJ.OS.PATH = {}


OJ.OS.PATH.abspath = function(path) {
    /**
     *> OJ.OS.PATH.abspath('path')
     * 
     * Returns a normalised absolute path.
     * 
     */
    var p = (/^\//.test(path) ? path : OJ.OS.environ.cwd + path).split('/'),
        abs = [],
        i = -1,
        result

    while (++i < p.length) {
        if (p[i].length !== 0) {
            if (/^\.\.$/.test(p[i]))
                abs.pop()
            else if (!/^\.$/.test(p[i]))
                abs.push(p[i])
        }
    }
    
    result = '/' + abs.join('/')
    
    if (path.lastIndexOf('/') === path.length - 1 && abs.length > 0)
        result += '/'
    
    
    return result

}



OJ.OS.PATH.isdir = function(path, callback) {
    /**
     *> OJ.OS.PATH.isdir('path', callback)
     * 
     * Calls callback with true if path is an existing directory,
     * otherwise false.
     * 
     */
    
    OJ.OS.read(OJ.OS.PATH.abspath(path + '/'), function(m) {
        if (typeof callback === 'function')
            callback(!OJ.isError(m))
    })

}

	

OJ.OS.PATH.basename = function(path) {
    /**
     *> OJ.OS.PATH.basename('path')
     * 
     * Return the base name of path.
     */
    
    if (/\/$/.test(path))
        return ''
        
    if (path === '')
        return null
    
    return path.split('/').pop()

}



OJ.OS.PATH.dirname = function(path) {
    /**
     *> OJ.OS.PATH.basename('path')
     * 
     * Return the base name of path.
     */
    
    if (/\/$/.test(path))
        return path
        
    if (path === '')
        return null
    
    path = path.split('/')
    path.pop()
    
    return path.join('/') + '/'

}




/**
=oj/file - File operations

The file module provides a File object for reading and writing to a file.

*/

    
OJ.__FILE_CONCAT_LIMIT__ = 90
OJ.__FILE_URI_LIMIT__    = 1801



OJ.File = function(path) {
    /**
     *=File - File object
     */
    
    var self = {}


    self.read = function (callback) {
        /**
         *> read(callback)
         *
         * Reads the file. In addition to the standard response properties, this
         * instance of File is returned as 'file'.
         *
         *. f.read(function (msg) {
         *.     if (!oj.isError(msg)) {
         *.         var read = msg.file.content;
         *.     }
         *. }
         * 
         */

        OJ.OS.read(self.path, function (response) {
            if (response.hasOwnProperty('error')) {
                if (typeof callback === 'function') {
                    response.file = self
                    callback(response)
                }
                return
            }
            self.content = response
            closed = false
            if (typeof callback === 'function') {
                response = {
                    success: 'successfully read',
                    file: self
                };
                callback(response)
            }
        })

        return self
    }


    self.write = function (string) {
        /**
         *> write('string')
         *
         * Write a string to the file. Due to buffering the string will not appear
         * in the server version of the file until flush() or close() are called.
         *
         *. f.write('append this to the files content');
         * 
         */

        self.content += string
    }


    self.flush = function (callback) {
        /**
         *> flush(callback)
         *
         * Flush the internal buffer.
         
         */

        var MAX_LEN = OJ.__FILE_URI_LIMIT__ - self.path.length,
            data = encodeURIComponent(self.content),
            len, parts = [],
            resps = 0,
            i

        // chop data up into parts for sending 
        while (data.length > MAX_LEN) {
            len = MAX_LEN

            // care we don't chop escapes (~X) or encodings (%40, %C3)
            while (data.charAt(len - 1) === '~')
                    len--
            while (data.lastIndexOf('%', len) > len - 3)
                len = data.lastIndexOf('%', len) - 1
            parts.push(data.slice(0, len))
            data = data.slice(len)
        }

        parts.push(data)

        var concatParts = function (concat) {
            if (typeof concat === 'undefined' || concat.hasOwnProperty('success')) {
                if (parts.length > 0) {
                    i = parts.slice(0, OJ.__FILE_CONCAT_LIMIT__)
                    parts = parts.slice(OJ.__FILE_CONCAT_LIMIT__)
                    if (parts.length > 0) {
                        resps = i[i.length - 1] + '.0'
                        i.push(resps)
                        parts.unshift(resps)
                    }
                    OJ.OS.concat(i, true, concatParts)
                    return
                }
                if (typeof callback === 'function') callback({
                    success: true,
                    file: self
                })
                return
            }
            if (typeof callback === 'function') {
                concat.file = self
                callback(concat)
            }
        }
        
        var multiWrite = function (write) {
            if (write.hasOwnProperty('error')) {
                resps += parts.length + 1
                if (typeof callback === 'function') {
                    write.file = self
                    callback(write)
                }
            }
            if (typeof callback === 'function')
                    callback({
                    multipart: resps,
                    file: self
                });
            
            if (++resps !== parts.length)
                    return

            for (i = 0; i < parts.length; i++)
                parts[i] = '/tmp' + self.path + '.' + i

            parts.push(self.path)
                concatParts()
        }
        
        if (parts.length > 1) {
            if (typeof callback === 'function')
                callback({multiparts: parts.length});

            // multipart write
            for (i = 0; i < parts.length; i++)
                OJ.OS.write('/tmp' + self.path + '.' + i, parts[i], multiWrite)

            return
        }

        // single part write
        OJ.OS.write(self.path, parts[0], function (write) {
            if (typeof callback === 'function') {
                if (write.hasOwnProperty('error')) {
                    write.file = self
                    return callback(write)
                }
                callback({
                    success: true,
                    file: self
                })
            }
        })
    }


    self.close = function (callback) {
        /**
         *> close(callback)
         *
         * Close the file. A closed file cannot be read or written to any more.
         */

        this.flush(function (m) {
            if (m.hasOwnProperty('success'))
                this.closed = true

            if (typeof callback === 'function')
                callback(m)
        })
    }


    self.closed = function () {
        /**
         *> closed()
         *
         * Returns true if file is closed; otherwise false.
         
         */

        return this.closed
    }


    self.truncate = function () {
        /**
         *> truncate()
         *
         * Truncates the files contents to an empty string.
         *
         */

        this.content = ''
    }


    
    self.closed  = false
    self.path    = OJ.OS.PATH.abspath(path)
    self.content = ''



    return self

}




require(['oj/term'], function() {



INSTALL = {}

INSTALL.out = null

INSTALL.multiparts = null

INSTALL.progress = null

INSTALL.files = [
    '/install/oj/__dir__.js',
    '/install/oj/cannon.js',
    '/install/oj/dat.js',
    '/install/oj/doc.js',
    '/install/oj/game.js',
    '/install/oj/ji.js',
    '/install/oj/math.js',
    '/install/oj/oj.html',
    '/install/oj/term.js',
    '/install/oj/test.js',
    '/install/oj/three.js'
]



INSTALL.read = function(path, fn) {
    /**
     * Reads a static file from current host.
     */
    
    var xhr = new XMLHttpRequest()
    xhr.open('GET', path)
    xhr.onreadystatechange = function () {
        if (typeof fn !== 'undefined' && this.status === 200 && this.readyState === 4)
            fn(this.responseText)
    }
    xhr.send()

}



INSTALL.finalise = function() {
    /**
     * Ends the installation with a nice message.
     */
    
    INSTALL.out.print('installation complete')
    INSTALL.out.print(OJ.element('a', {href: '/oj/term'}, ['start']))

}



INSTALL.installFile = function(path) {

    INSTALL.progress = OJ.element(INSTALL.out.print(path + ' '), 'install_progress', ['0%'])
    INSTALL.progress.style.color = '#e06c1f'
    INSTALL.read(path, function (m) {
        var dst = OJ.File(path.replace('/install', ''))
        dst.write(m)
        dst.close(function (m) {
            if (m.hasOwnProperty('error'))
                return INSTALL.out.print(m)
            else if (m.hasOwnProperty('multiparts'))
                INSTALL.multiparts = m.multiparts
            else if (m.hasOwnProperty('multipart')) {
                INSTALL.progress.innerHTML = ~~((m.multipart / INSTALL.multiparts) * 100) + '%'
            } else if (m.hasOwnProperty('success')) {
                INSTALL.progress.innerHTML = '100%'
                INSTALL.progress.style.color = '#00ff00'
                if (INSTALL.files.length > 0)
                     INSTALL.installFile(INSTALL.files.shift())
                else
                     INSTALL.finalise()
            }
        })
    })

}



INSTALL.install = function() {

    OJ.OS.mkdir('/oj', function () {
        INSTALL.installFile(INSTALL.files.shift())
    })

}



OJ.element(document.head, 'syle', {'type': 'text/css'}, [
    'html {',
    '  height: 100%;',
    '}',
    'body {',
    '  height: 100%;',
    '}',
    '.install_progress {',
    '  min-width: 2px',
    '  color: green',
    '}'
])

OJ.OS.identity(document.location, function (m) {

    if (m.hasOwnProperty('login')) {
        document.location = m.login
        return
    }

    INSTALL.out = TERM.Term(document.body)
    OJ.OS.environ.user = m
    INSTALL.out.print(OJ.version + ' installation')
    OJ.OS.listdir('/', function (m) {

        if (m.hasOwnProperty('error') && m.error.indexOf('/: No such') === 0) {
            INSTALL.out.print('no previous installation found')
            OJ.OS.system('/', ['Z/'], function (m) {
                if (m.hasOwnProperty('error'))
                    return INSTALL.out.print(m)
                INSTALL.out.print('format successful')
                INSTALL.install()
            })

        } else {

            INSTALL.out.print('previous installation found, skipping format')
            INSTALL.install()

        }

    })

})




})



})()</script>
</body>
